#include "esp_log.h"
#include "AsyncClient.hpp"
#include "AsyncServer.hpp"
#include "AsyncTCP.hpp"

#define TAG "AsyncServer"

AsyncServer::AsyncServer(ip_addr_t addr, uint16_t port)
    : m_port(port)
    , m_addr(addr)
    , m_nodelay(false)
    , m_pcb(nullptr)
    , on_connected_handler(nullptr)
    , on_connected_arg(nullptr)
{
    m_async = Async::GetInstance();
    init_client_pool();
}

AsyncServer::AsyncServer(uint16_t port)
    : m_port(port)
    , m_nodelay(false)
    , m_pcb(nullptr)
    , on_connected_handler(nullptr)
    , on_connected_arg(nullptr)
{
    m_addr = IPADDR4_INIT(0);
    m_async = Async::GetInstance();
    init_client_pool();
}

AsyncServer::~AsyncServer()
{
    end();
}

/// @brief 启动异步服务器
void AsyncServer::begin()
{
    if (m_pcb != nullptr) {
        ESP_LOGE(TAG, "协议控制块PCB不为空");
        return;
    }

    m_pcb = tcp_new_ip_type(IPADDR_TYPE_V4);
    if (m_pcb == nullptr) {
        ESP_LOGE(TAG, "创建PCB失败");
        return;
    }

    if (bind() != ERR_OK) {
        abort_tcp(m_pcb);
        m_pcb = nullptr;
        ESP_LOGE(TAG, "PCB绑定IP、Port时出错");
        return;
    }

    tcp_api_call_t msg;
    msg.pcb = m_pcb;
    msg.listen_backlog = CONFIG_SERVER_BACKLOG_LEN;
    tcpip_api_call([](tcpip_api_call_data * data) -> err_t {
        auto* msg = reinterpret_cast<tcp_api_call_t*>(data);
        msg->pcb = tcp_listen_with_backlog(msg->pcb, msg->listen_backlog);
        return ERR_OK;
    },
    (tcpip_api_call_data*)&msg
                  );
    m_pcb = msg.pcb;

    tcp_arg(m_pcb, this);
    tcp_accept(m_pcb, [](void* arg, tcp_pcb * pcb, err_t err) -> err_t {
        if (err != ERR_OK || pcb == nullptr) {
            ESP_LOGE(TAG, "连接错误, err=%d, pcb=%d", err, (int)pcb);
            if (pcb) {
                tcp_abort(pcb);
            }
            return ERR_ABRT;
        }
        auto* server = reinterpret_cast<AsyncServer*>(arg);
        auto* client = server->get_client_from_pool();
        if (client == nullptr)
        {
            ESP_LOGE(TAG, "连接池耗尽，拒绝新连接.");
            tcp_abort(pcb);
            return ERR_ABRT;
        }
        client->init(pcb);
        client->set_nodelay(server->get_nodelay());
        return server->create_accept_event(arg, client);
    });
}

/// @brief 关闭异步TCP服务器
void AsyncServer::end()
{
    if (m_pcb) {
        tcp_accept(m_pcb, nullptr);
        tcp_arg(m_pcb, nullptr);
        if (close_tcp(m_pcb) != ERR_OK) {
            abort_tcp(m_pcb);
        }
        m_pcb = nullptr;
    }
    AsyncClient* c;
    for (int i = 0; i < CONFIG_CLIENT_POOL_LEN; i++) {
        xQueueReceive(m_client_pool, &c, 0);
        if (c != nullptr) {
            c->delete_instance();
        }
    }
    vQueueDelete(m_client_pool);
    m_client_pool = nullptr;
}

/// @brief 设置连接建立时回调函数及其参数
/// @param handler 回调函数
/// @param arg 传递给回调函数的参数
void AsyncServer::set_connected_handler(AcConnectHandler handler, void* arg)
{
    on_connected_handler = handler;
    on_connected_arg = arg;
}

/// @brief 设置连接建立时默认是否采用延迟发送
/// @param nodelay true表示延迟发送（减少发送频度）
void AsyncServer::set_nodelay(bool nodelay)
{
    m_nodelay = nodelay;
}

/// @brief 获取服务器延迟发送启用情况
/// @return true表示启用延迟发送
bool AsyncServer::get_nodelay()
{
    return m_nodelay;
}

/// @brief 客户端连接处理：调用用户注册的客户端连接处理函数
err_t AsyncServer::handle_accepted_event(AsyncClient* client)
{
    client->event_count_sub();
    if (on_connected_handler) {
        on_connected_handler(on_connected_arg, client);
    }
    return ERR_OK;
}

/// @brief 获取当前服务器连接状态
tcp_state AsyncServer::get_connection_state()
{
    return m_pcb ? m_pcb->state : CLOSED;
}

/// @brief 初始化对象池
uint8_t AsyncServer::init_client_pool()
{
    m_client_pool = xQueueCreate(CONFIG_CLIENT_POOL_LEN, sizeof(AsyncClient*));
    if (m_client_pool == nullptr) {
        ESP_LOGE(TAG, "创建对象池队列失败");
        return 0;
    }
    int i;
    auto async = Async::GetInstance();
    std::lock_guard<std::mutex> lock(m_pool_mutex);
    for (i = 0; i < CONFIG_CLIENT_POOL_LEN; i++) {
        auto* client = new AsyncClient(async, this);
        if (client == nullptr) {
            ESP_LOGW(TAG, "创建对象失败，初始化池提前结束。ID=%d", i);
            return i;
        }
        client->reset();
        if (xQueueSend(m_client_pool, &client, portMAX_DELAY) != pdPASS) {
            ESP_LOGE(TAG, "对象存入对象池失败，释放该对象.");
            client->delete_instance();
            return i;
        }
    }
    return i;
}

/// @brief 在配置的时间内从client实例池获取实例
/// @return client指针，失败时返回nullptr
AsyncClient* AsyncServer::get_client_from_pool()
{
    std::lock_guard<std::mutex> lock(m_pool_mutex);
    AsyncClient* client = nullptr;
    xQueueReceive(m_client_pool, &client, pdMS_TO_TICKS(CONFIG_CONNECT_TIMEOUT * 1000));
    return client;
}

void AsyncServer::push_client_to_pool(AsyncClient* client)
{
    client->reset();
    if (xQueueSend(m_client_pool, &client, portMAX_DELAY) != pdPASS) {
        client->delete_instance();
        ESP_LOGW(TAG, "回收client实例时失败，删除对象!");
    }
}

err_t AsyncServer::create_accept_event(void* arg, AsyncClient* client)
{
    if (arg == nullptr || client == nullptr) {
        return ESP_ERR_INVALID_ARG;
    }
    auto* e = m_async->get_event_from_pool();
    if (e == nullptr) {
        ESP_LOGE(TAG, "从事件池取出事件失败");
        return ESP_FAIL;
    }
    e->type = LWIP_TCP_ACCEPT;
    e->arg = arg;
    e->accep_client = client;
    if (m_async->send_event_to_queue(e) != true) {
        ESP_LOGE(TAG, "发送事件到队列中失败，事件被丢弃！");
        client->delete_instance();
        m_async->push_event_to_pool(e);
        return ESP_FAIL;
    }
    client->event_count_add();
    return ESP_OK;
}

/// @brief 将协议控制块PCB与指定的IP:Port绑定
err_t AsyncServer::bind()
{
    tcp_api_call_t msg;
    msg.pcb = m_pcb;
    msg.bind_addr = &m_addr;
    msg.bind_port = m_port;
    return tcpip_api_call([](tcpip_api_call_data * data) -> err_t {
        auto* msg = reinterpret_cast<tcp_api_call_t*>(data);
        return tcp_bind(msg->pcb, msg->bind_addr, msg->bind_port);
    },
    (tcpip_api_call_data*)&msg
                         );
}